package org.itzixi.filter;


import cn.hutool.core.util.StrUtil;
import com.google.gson.Gson;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.itzixi.grace.result.GraceJSONResult;
import org.itzixi.grace.result.ResponseStatusEnum;
import org.itzixi.utils.IPUtil;
import org.itzixi.utils.RedisOperator;
import org.itzixi.utils.RenderErrorMsgUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Component
@Slf4j
//@ConfigurationProperties(prefix = "black-ip")
@RefreshScope
public class IPLimitFilter implements GlobalFilter, Ordered {
    @Resource
    private RedisOperator redisOperator;

    @Value("${black-ip.timeInterval}")
    private Integer timeInterval;

    @Value("${black-ip.limitTimes}")
    private Integer limitTimes;

    @Value("${black-ip.continueCounts}")
    private Integer continueCounts;
    @Override
    @RefreshScope
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("timeInterval：{}", timeInterval);
        log.info("limitTimes：{}", limitTimes);
        log.info("continueCounts：{}", continueCounts);
        return doLimit(exchange, chain);
    }


    private Mono<Void> doLimit(ServerWebExchange exchange, GatewayFilterChain chain){
        ServerHttpRequest request = exchange.getRequest();

        String requestPath = request.getURI().getPath();
//        request.get
        String ip = IPUtil.getIP(request);


        final String ipRedisKey = Stream.of("gateway-ip", ip).collect(Collectors.joining(StrUtil.COLON));
        // 黑名单的redisKey
        final String blackIpRedisKey = Stream.of("gateway-ip", "limit", ip).collect(Collectors.joining(StrUtil.COLON));

        // 获取当前的ip并且查询还剩下多少时间，如果时间大于0，则表示还在黑名单中
        long leftTime = redisOperator.ttl(blackIpRedisKey);
        if (leftTime > 0) return RenderErrorMsgUtil.renderErrorMsg(exchange, ResponseStatusEnum.SYSTEM_ERROR_BLACK_IP);


        long requestCounts = redisOperator.increment(ipRedisKey, 1);
        // 判段是否是第一次请求,如果是给一个续期时间
        if (requestCounts == 1L) {
//            final int timeInterval = 20;
            redisOperator.expire(ipRedisKey, timeInterval);
        }

        //如果在续期时间内请求次数大于限制的连续请求数，那么设置为黑名单IP
//        final int continueCounts = 3;
        if (requestCounts > continueCounts){
//            final int limitTimes = 30;
            redisOperator.set(blackIpRedisKey, blackIpRedisKey, limitTimes);
            return RenderErrorMsgUtil.renderErrorMsg(exchange, ResponseStatusEnum.SYSTEM_ERROR_BLACK_IP);
        }

        return chain.filter(exchange);
    }

//    private Mono<Void> renderErrorMsg(ServerWebExchange exchange, ResponseStatusEnum responseStatusEnum){
//        ServerHttpResponse response = exchange.getResponse();
//        GraceJSONResult jsonResult = GraceJSONResult.exception(responseStatusEnum);
//        HttpHeaders headers = response.getHeaders();
//        final String jsonMimeType = "Content-Type";
//        if (!headers.containsKey(jsonMimeType)){
//            headers.add(jsonMimeType, MimeTypeUtils.APPLICATION_JSON_VALUE);
//        }
//
//        // 设置状态码为500
//        response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
//
//        String jsonStr = new Gson().toJson(jsonResult);
//        DataBuffer dataBuffer = response.bufferFactory().wrap(jsonStr.getBytes(StandardCharsets.UTF_8));
//        return response.writeWith(Mono.just(dataBuffer));
//    }

    @Override
    public int getOrder() {
        return 1;
    }
}
